define(function(){
    /** 配置参数
     * scope.routeRules = [
         {
             when: '/doc/:key*',
             moduleid: 'modules/doc/doc.js'
         },
         {
             redirect: '/list'
         }
     ]
     */
    var scope = this, $$ = bowlder, supportHtml5 = !!window.history.pushState;
    var root, wrapRoot, wrapClone, routeWidget, _widget;
    var widgets = {};
    var routeAbort; //当route切换时，通知旧组件停止操作
    scope.html = "";
    
    scope.update = function(params, rule){
        //更新当前组件的scope.$routeParams并执行scope.routeInit(params)
        var widget, moduleid = rule.moduleid;
        if(!root || !root.parentNode) return;
        if(!moduleid){
            widget = routeWidget;
        }else{
            widget = widgets[moduleid];
        }
        if(!widget){
            var wrap = wrapClone.cloneNode(false);
            root.parentNode.replaceChild(wrap, root);
            widget = widgets[moduleid] = routeWidget.load(moduleid, wrap);
            root = wrap;
        }else{
            if(widget != _widget){
                root.parentNode.replaceChild(widget.$root[0], root);
            }
            root = widget.$root[0];
        }
        if(widget != routeWidget){
            routeWidget.children.splice(0, 1, widget);
        }
        _widget = widget;
        if(routeAbort) routeAbort.resolve();
        routeAbort = ($$.q || $$.$q).defer();
        params.$abort = routeAbort.promise;
        _widget.extend({
            $routeParams: params
        });
        _widget.ready(function(){
            if(params.$abort != routeAbort.promise) return; //路由已切到另一个
            var _scope = this.scope;
            //触发子组件的route.updated事件
            var subEmit = function(_w){
                $$.each(_w.children, function(w){
                    if(!w.scope.hasOwnProperty("routeRules")){
                        w.emit("route.updated", params);
                        subEmit(w);
                    }
                });
            }
            subEmit(_widget);
            if(_scope.hasOwnProperty('routeInit')){
                if(_scope.routeInit.call(this, params) === false){
                    return;
                }
            }
            _scope.$refresh();
        });
    }
    scope.init = function(widget){
        var oldHash;
        routeWidget = widget;
        root = wrapRoot = widget.$root[0];
        root.removeAttribute("bd-id"); //避免始终占用同一个组件对象
        wrapClone = root.cloneNode(false);

        function _routechange(_hash){
            if(!scope.hasOwnProperty("routeRules") || !$$.isArray(scope.routeRules)) return;
            var rules = scope.routeRules;
            var hash = _hash || (scope.state.routeType == "pathname" && supportHtml5 ? location.pathname : location.hash.replace(/^#/, ''));
            var routeParams = {$refer: oldHash};
            oldHash = hash;
            for(var i = 0, len = rules.length; i < len; i ++){
                var rule = rules[i];
                if(rule.redirect){
                    if(!_hash){ //避免redirect陷入死循环
                        if(!rule.initOnly || !_widget){ //多route共存时，initOnly可避免误触发
                            if($$.isFunction(rule.redirect)){
                                rule.redirect();
                            }else{
                                _routechange(rule.redirect);
                            }
                        }
                    }
                    return;
                }
                var patt = getPattern(rule), matchResults;
                if(patt && (matchResults = patt.exec(hash))){
                    $$.extend(routeParams, rule.params);
                    $$.each(matchResults, function(val, i){
                        if(rule.params[i]) routeParams[rule.params[i]] = decodeURIComponent(val);
                    });
                    scope.update(routeParams, rule);
                    return;
                }
            }
        }
        var routechange = $$.debounce(_routechange, $$.isNumber(scope.state.debounceTime) ? scope.state.debounceTime : 100, true);
        if(scope.state.routeType == "pathname" && supportHtml5){
            window.addEventListener('popstate', function(event) {
                routechange();
            });
        }else{
            $$(window).bind("hashchange", function(){
                routechange();
            });
        }
        //某些应用场景下，页面状态变化不引发hashchange;
        //此时如果希望恢复原始状态，需要手动执行$$.emit("route.change")
        $$.on("route.change", function(){
            routechange(); //已做debounce处理，不会与hashchange重复触发
        });
        
        routechange();
        
        function getPattern(rule){
            if(!rule.patt && rule.when){
                rule.params = ['$match'];
                var path = rule.when.replace(/:([A-z]\w*)(\*)?/g, function(match, key, greedy){
                    rule.params.push(key);
                    return greedy ? '(\\S*)' : '(\\S*?)'
                }).replace(/\?\)$/, '?)(?=/|$)');
                rule.patt = new RegExp(path);
            }
            return rule.patt;
        }
    };
});
